package org.niugang.security.common.aop;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.niugang.security.common.annotation.LogApi;
import org.niugang.security.log.pojo.LogDO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import org.springframework.data.redis.core.RedisTemplate;

/**
 * 日志注解解析类
 *
 * @author niugang
 */
@Aspect
@Component
public class LogAscept {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Around("@annotation(org.niugang.security.common.annotation.LogApi)")
    public Object aroundAdvice(ProceedingJoinPoint pjd) throws Throwable {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes r = (ServletRequestAttributes) requestAttributes;
        HttpServletRequest request = r.getRequest();
        long start = System.currentTimeMillis();
        Object proceed = pjd.proceed();
        long end = System.currentTimeMillis();
        String ip = getIpAddr(request);
        int port = request.getRemotePort();
        MethodSignature signature = (MethodSignature) pjd.getSignature();
        Method method = signature.getMethod();
        LogApi logApi = method.getAnnotation(LogApi.class);
        String name = SecurityContextHolder.getContext().getAuthentication().getName();
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:dd");
        String format = dateTimeFormatter.format(LocalDateTime.now());
        LogDO logEntity = LogDO.builder().account(name).ip(ip).port(port).time(format).type(logApi.type()).value(logApi.value()).useTime(end - start).build();
        // 调用redis发布消息
        messageQueue(logEntity);
        // 必须得有返回值，否则不能往下执行
        return proceed;
    }

    /**
     * 方法调用失败
     *
     * @param pjd pjd
     */
    @AfterThrowing("@annotation(org.niugang.security.common.annotation.LogApi)")
    public void afterThrowing(JoinPoint pjd) {


    }

    /**
     * @param logEntity logEntity
     */
    private void messageQueue(LogDO logEntity) throws JsonProcessingException {
        redisTemplate.convertAndSend("log_queue", objectMapper.writeValueAsString(logEntity));

    }

    /**
     * @param request request
     * @return String
     */
    private static String getIpAddr(HttpServletRequest request) {

        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }

}